/*-------------------------------------------------------------------------
 *
 * typcache.h
 *	  类型缓存定义。
 *
 * 类型缓存存在是为了加速查找某些关于数据类型的信息，这些信息并不直接可从类型的 pg_type 行获取。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/utils/typcache.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef TYPCACHE_H
#define TYPCACHE_H

#include "access/tupdesc.h"
#include "fmgr.h"
#include "storage/dsm.h"
#include "utils/dsa.h"


/* DomainConstraintCache 是一个仅在 typcache.c 中已知的不透明结构 */
typedef struct DomainConstraintCache DomainConstraintCache;

/* TypeCacheEnumData 是一个仅在 typcache.c 中已知的不透明结构 */
struct TypeCacheEnumData;

typedef struct TypeCacheEntry
{
	/* typeId 是哈希查找键，必须放在第一位 */
	Oid			type_id;		/* 数据类型的 OID */

	uint32		type_id_hash;	/* OID 的哈希值 */

	/* 从 pg_type 行复制的一些附属信息 */
	int16		typlen;
	bool		typbyval;
	char		typalign;
	char		typstorage;
	char		typtype;
	Oid			typrelid;
	Oid			typsubscript;
	Oid			typelem;
	Oid			typcollation;

	/*
	 * 从 opfamily 条目获得的信息
	 *
	 * 如果找不到匹配项，或者信息尚未请求，这些将是 InvalidOid。
	 * 还请注意，对于数组和复合类型，typcache.c 会检查
	 * 其中包含的类型是否可比较或可哈希，然后才允许 eq_opr 等被设定。
	 */
	Oid			btree_opf;		/* 默认 btree opclass 的家族 */
	Oid			btree_opintype; /* 默认 btree opclass 的 opcintype */
	Oid			hash_opf;		/* 默认哈希 opclass 的家族 */
	Oid			hash_opintype;	/* 默认哈希操作类的 opcintype */
	Oid			eq_opr;			/* 等于运算符 */
	Oid			lt_opr;			/* 小于运算符 */
	Oid			gt_opr;			/* 大于运算符 */
	Oid			cmp_proc;		/* btree 比较函数 */
	Oid			hash_proc;		/* 哈希计算函数 */
	Oid			hash_extended_proc; /* 扩展哈希计算函数 */

	/*
	 * 为等于运算符、btree 比较函数和哈希计算函数预设 fmgr 调用信息。它们保存在类型缓存中，以避免在对 array_eq、array_cmp、hash_array 等函数的重复调用中出现内存泄漏问题。目前尚无维护 lt_opr 或 gt_opr 的调用信息的必要。
	 */
	FmgrInfo	eq_opr_finfo;
	FmgrInfo	cmp_proc_finfo;
	FmgrInfo	hash_proc_finfo;
	FmgrInfo	hash_extended_proc_finfo;

	/*
	 * 如果是复合类型（行类型），则为元组描述符；如果不是复合类型或信息尚未请求，则为 NULL。（注意：这是一个引用计数的元组描述符。）
	 *
	 * 为简化缓存依赖信息，tupDesc_identifier 是这个元组描述符的唯一标识符，在进程的生命周期内保持不变，每次元组描述符发生变化时都会改变。尚未确定时为零。
	 */
	TupleDesc	tupDesc;
	uint64		tupDesc_identifier;

	/*
	 * 请求 TYPECACHE_RANGE_INFO 时计算的字段。如果不是范围类型或信息尚未请求，则为零。请注意，rng_cmp_proc_finfo 可能与元素类型的默认 btree 比较函数不同。
	 */
	struct TypeCacheEntry *rngelemtype; /* 范围的元素类型 */
	Oid			rng_collation;	/* 比较的排序规则（如果有） */
	FmgrInfo	rng_cmp_proc_finfo; /* 比较函数 */
	FmgrInfo	rng_canonical_finfo;	/* 标准化函数（如果有） */
	FmgrInfo	rng_subdiff_finfo;	/* 差异函数（如果有） */

	/*
	 * 请求 TYPECACHE_MULTIRANGE_INFO 时计算的字段。
	 */
	struct TypeCacheEntry *rngtype; /* multirange 的基础类型 */

	/*
	 * 如果是域类型，则为域的基础类型和 typmod。如果不是域，或信息尚未请求，则为零。
	 */
	Oid			domainBaseType;
	int32		domainBaseTypmod;

	/*
	 * 如果是域类型，则为域约束数据。如果不是域，或域没有约束，或信息尚未请求，则为 NULL。
	 */
	DomainConstraintCache *domainData;

	/* 私有数据，仅供 typcache.c 内部使用 */
	int			flags;			/* 关于我们计算的内容的标志 */

	/*
	 * 关于枚举类型的私有信息。如果不是枚举，或信息尚未请求，则为 NULL。
	 */
	struct TypeCacheEnumData *enumData;

	/* 我们还维护了所有已知的域类型缓存条目的列表 */
	struct TypeCacheEntry *nextDomain;
} TypeCacheEntry;

/* 位标志，指示给定调用者需要设置的字段 */
#define TYPECACHE_EQ_OPR			0x00001
#define TYPECACHE_LT_OPR			0x00002
#define TYPECACHE_GT_OPR			0x00004
#define TYPECACHE_CMP_PROC			0x00008
#define TYPECACHE_HASH_PROC			0x00010
#define TYPECACHE_EQ_OPR_FINFO		0x00020
#define TYPECACHE_CMP_PROC_FINFO	0x00040
#define TYPECACHE_HASH_PROC_FINFO	0x00080
#define TYPECACHE_TUPDESC			0x00100
#define TYPECACHE_BTREE_OPFAMILY	0x00200
#define TYPECACHE_HASH_OPFAMILY		0x00400
#define TYPECACHE_RANGE_INFO		0x00800
#define TYPECACHE_DOMAIN_BASE_INFO			0x01000
#define TYPECACHE_DOMAIN_CONSTR_INFO		0x02000
#define TYPECACHE_HASH_EXTENDED_PROC		0x04000
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO	0x08000
#define TYPECACHE_MULTIRANGE_INFO			0x10000

/* 此值将不等于任何有效的元组描述符标识符，也不为 0 */
#define INVALID_TUPLEDESC_IDENTIFIER ((uint64) 1)

/*
 * 希望维持对域约束集长久引用的调用者必须将其存储在这些之一中。使用 InitDomainConstraintRef() 和 UpdateDomainConstraintRef() 来管理它。注意：DomainConstraintState 被认为是一种可执行表达式类型，因此在 execnodes.h 中定义。
 */
typedef struct DomainConstraintRef
{
	List	   *constraints;	/* DomainConstraintState 节点的列表 */
	MemoryContext refctx;		/* 持有 DomainConstraintRef 的上下文 */
	TypeCacheEntry *tcache;		/* 域类型的 typcache 条目 */
	bool		need_exprstate; /* 调用者是否需要 check_exprstate？ */

	/* 管理数据 --- 将这些字段视为 typcache.c 的私有 */
	DomainConstraintCache *dcc; /* 当前约束，如果没有则为 NULL */
	MemoryContextCallback callback; /* 用于完成后的引用计数释放 */
} DomainConstraintRef;

typedef struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry;

extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags);

extern void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref,
									MemoryContext refctx, bool need_exprstate);

extern void UpdateDomainConstraintRef(DomainConstraintRef *ref);

extern bool DomainHasConstraints(Oid type_id);

extern TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod);

extern TupleDesc lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod,
												bool noError);

extern TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod);

extern TupleDesc lookup_rowtype_tupdesc_domain(Oid type_id, int32 typmod,
											   bool noError);

extern void assign_record_type_typmod(TupleDesc tupDesc);

extern uint64 assign_record_type_identifier(Oid type_id, int32 typmod);

extern int	compare_values_of_enum(TypeCacheEntry *tcache, Oid arg1, Oid arg2);

extern size_t SharedRecordTypmodRegistryEstimate(void);

extern void SharedRecordTypmodRegistryInit(SharedRecordTypmodRegistry *,
										   dsm_segment *segment, dsa_area *area);

extern void SharedRecordTypmodRegistryAttach(SharedRecordTypmodRegistry *);

#endif							/* TYPCACHE_H */
